package owlapps2012.owlToSql.events.p4;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.protege.editor.owl.OWLEditorKit;
import org.protege.editor.owl.model.inference.ReasonerPreferences.OptionalInferenceTask;
import org.protege.editor.owl.ui.editor.OWLObjectEditor;
import org.protege.editor.owl.ui.frame.OWLFrame;
import org.protege.editor.owl.ui.frame.OWLFrameSectionRow;
import org.protege.editor.owl.ui.frame.cls.AbstractOWLClassAxiomFrameSection;
import org.protege.editor.owl.ui.frame.cls.OWLEquivalentClassesAxiomFrameSectionRow;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLObject;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChange;
import org.semanticweb.owlapi.util.CollectionFactory;

/**
* Author: Piotr Nowara<br>
* piotrnowara@gmail.com<br>
* code made available under Mozilla Public License (http://www.mozilla.org/MPL/MPL-1.1.html)<br>
* copyright 2013, Piotr Nowara<br>
*/
public class LinkedFactsCategoryDefinitionFrameSection  extends AbstractOWLClassAxiomFrameSection<OWLEquivalentClassesAxiom, OWLClassExpression> 
{

    private static final String LABEL = "Definition";

    private Set<OWLClassExpression> added = new HashSet<OWLClassExpression>();

    private boolean inferredEquivalentClasses = true;


    public LinkedFactsCategoryDefinitionFrameSection(OWLEditorKit editorKit, OWLFrame<OWLClass> frame) {
    	super(editorKit, LABEL, "Fact definition", frame);
    }
    
    protected void clear() {
        added.clear();
    }

        
    /*
     * (non-Javadoc)
     * @see org.protege.editor.owl.ui.frame.cls.AbstractOWLClassAxiomFrameSection#addAxiom(org.semanticweb.owlapi.model.OWLAxiom, org.semanticweb.owlapi.model.OWLOntology)
     * 
     * Code below has been copied from org.protege.editor.owl.ui.frame.cls.OWLEquivalentClassesAxiomFrameSection because it is impossible to extend that class due to lack of an appropriate visible constructor.
     */

    protected void addAxiom(OWLEquivalentClassesAxiom ax, OWLOntology ontology) {
        addRow(new OWLEquivalentClassesAxiomFrameSectionRow(getOWLEditorKit(),
                                                            this,
                                                            ontology,
                                                            getRootObject(),
                                                            ax));
        for (OWLClassExpression desc : ax.getClassExpressions()) {
            added.add(desc);
        }
    }


	protected Set<OWLEquivalentClassesAxiom> getClassAxioms(OWLClassExpression descr, OWLOntology ont) {
        if (!descr.isAnonymous()){
            return ont.getEquivalentClassesAxioms(descr.asOWLClass());
        }
        else{
            Set<OWLEquivalentClassesAxiom> axioms = new HashSet<OWLEquivalentClassesAxiom>();
            for (OWLAxiom ax : ont.getGeneralClassAxioms()){
                if (ax instanceof OWLEquivalentClassesAxiom &&
                    ((OWLEquivalentClassesAxiom)ax).getClassExpressions().contains(descr)){
                    axioms.add((OWLEquivalentClassesAxiom)ax);
                }
            }
            return axioms;
        }
    }


    protected void refillInferred() {
        if (!inferredEquivalentClasses) {
            return;
        }
        getOWLModelManager().getReasonerPreferences().executeTask(OptionalInferenceTask.SHOW_INFERRED_EQUIVALENT_CLASSES, 
                                                                  new Runnable() {

            public void run() {
            	if (!getOWLModelManager().getReasoner().isConsistent()) {
            		return;
            	}
            	OWLClass nothing = getOWLModelManager().getOWLDataFactory().getOWLNothing();
                if (!getOWLModelManager().getReasoner().isSatisfiable(getRootObject()) && !nothing.equals(getRootObject())) {
                    addRow(new OWLEquivalentClassesAxiomFrameSectionRow(getOWLEditorKit(),
                    		LinkedFactsCategoryDefinitionFrameSection.this,
                                                                        null,
                                                                        getRootObject(),
                                                                        getOWLDataFactory().getOWLEquivalentClassesAxiom(CollectionFactory.createSet(getRootObject(),
                                                                                                                                                     nothing))));
                }
                else{
                    for (OWLClassExpression cls : getOWLModelManager().getReasoner().getEquivalentClasses(getRootObject())) {
                        if (!added.contains(cls) && !cls.equals(getRootObject())) {
                            addRow(new OWLEquivalentClassesAxiomFrameSectionRow(getOWLEditorKit(),
                            		LinkedFactsCategoryDefinitionFrameSection.this,
                                                                                null,
                                                                                getRootObject(),
                                                                                getOWLDataFactory().getOWLEquivalentClassesAxiom(CollectionFactory.createSet(getRootObject(),
                                                                                                                                                             cls))));
                        }
                    }
                }
            }
        });

    }


    protected OWLEquivalentClassesAxiom createAxiom(OWLClassExpression object) {
        return getOWLDataFactory().getOWLEquivalentClassesAxiom(CollectionFactory.createSet(getRootObject(), object));
    }


    public OWLObjectEditor<OWLClassExpression> getObjectEditor() {
        return getOWLEditorKit().getWorkspace().getOWLComponentFactory().getOWLClassDescriptionEditor(null, AxiomType.EQUIVALENT_CLASSES);
    }

    public boolean checkEditorResults(OWLObjectEditor<OWLClassExpression> editor) {
    	Set<OWLClassExpression> equivalents = editor.getEditedObjects();
    	return equivalents.size() != 1 || !equivalents.contains(getRootObject());
    }
    
    @Override
    public void handleEditingFinished(Set<OWLClassExpression> editedObjects) {
    	editedObjects = new HashSet<OWLClassExpression>(editedObjects);
    	editedObjects.remove(getRootObject());
    	super.handleEditingFinished(editedObjects);
    }

    public boolean canAcceptDrop(List<OWLObject> objects) {
        for (OWLObject obj : objects) {
            if (!(obj instanceof OWLClassExpression)) {
                return false;
            }
        }
        return true;
    }


    public boolean dropObjects(List<OWLObject> objects) {
        List<OWLOntologyChange> changes = new ArrayList<OWLOntologyChange>();
        for (OWLObject obj : objects) {
            if (obj instanceof OWLClassExpression) {
                OWLClassExpression desc = (OWLClassExpression) obj;
                OWLAxiom ax = getOWLDataFactory().getOWLEquivalentClassesAxiom(CollectionFactory.createSet(getRootObject(),
                                                                                                           desc));
                changes.add(new AddAxiom(getOWLModelManager().getActiveOntology(), ax));
            }
            else {
                return false;
            }
        }
        getOWLModelManager().applyChanges(changes);
        return true;
    }

    @Override
    protected boolean isResettingChange(OWLOntologyChange change) {
    	return change.isAxiomChange() &&
    			change.getAxiom() instanceof OWLEquivalentClassesAxiom &&
    			((OWLEquivalentClassesAxiom) change.getAxiom()).getClassExpressions().contains(getRootObject());
    }



	/**
     * Obtains a comparator which can be used to sort the rows
     * in this section.
     * @return A comparator if to sort the rows in this section,
     *         or <code>null</code> if the rows shouldn't be sorted.
     */
    public Comparator<OWLFrameSectionRow<OWLClassExpression, OWLEquivalentClassesAxiom, OWLClassExpression>> getRowComparator() {
        return null;
    }

}
